﻿namespace ImageProcessing
{
    using System;
    using System.Collections.Generic;
    using System.Drawing;
    using System.Drawing.Imaging;
    using System.IO;
    using System.Linq;
    using System.Text;
    using System.Threading;

    /// <summary>
    /// Class containing save images functions.
    /// </summary>
    public class SaveImages
    {
        /// <summary>
        /// Saves the image.
        /// </summary>
        /// <param name="filePath">The file path.</param>
        /// <param name="bmp">The BMP.</param>
        /// <returns>
        /// If saved succefully returns true, else false
        /// </returns>
        public static bool SaveImage(string filePath, Bitmap bmp)
        {
            string[] fileData = filePath.Split('.');
            if (fileData[fileData.GetLength(0) - 1].ToLower() == "bmp")
            {
                bmp.Save(filePath, System.Drawing.Imaging.ImageFormat.Bmp);
            }
            else if (fileData[fileData.GetLength(0) - 1].ToLower() == "jpg")
            {
                bmp.Save(filePath, System.Drawing.Imaging.ImageFormat.Jpeg);
            }
            else if (fileData[fileData.GetLength(0) - 1].ToLower() == "gif" || fileData[fileData.GetLength(0) - 1].ToLower() == "png")
            {
                bmp.Save(filePath, System.Drawing.Imaging.ImageFormat.Gif);
            }
            else if (fileData[fileData.GetLength(0) - 1].ToLower() == "png")
            {
                bmp.Save(filePath, System.Drawing.Imaging.ImageFormat.Png);
            }
            else if (fileData[fileData.GetLength(0) - 1].ToLower() == "pgm")
            {
                SaveP5(filePath, bmp);
            }
            else if (fileData[fileData.GetLength(0) - 1].ToLower() == "p6")
            {
                filePath = string.Empty;
                for (int i = 0; i < fileData.GetLength(0) - 1; i++)
                {
                    filePath += fileData[i] + '.';
                }

                filePath += "ppm";
                SaveP6(filePath, bmp);
            }
            else if (fileData[fileData.GetLength(0) - 1].ToLower() == "p3")
            {
                filePath = string.Empty;
                for (int i = 0; i < fileData.GetLength(0) - 1; i++)
                {
                    filePath += fileData[i] + '.';
                }

                filePath += "ppm";
                SaveP3(filePath, bmp);
            }

            return true;
        }

        /// <summary>
        /// Saves the p6.
        /// </summary>
        /// <param name="filePath">The file path.</param>
        /// <param name="bmp">The BMP.</param>
        private static void SaveP6(string filePath, Bitmap bmp)
        {
            TextWriter textWriter = new StreamWriter(filePath);
            textWriter.Write("P6\n# Image saved by PLACEHOLDER team.\n");
            textWriter.Write(bmp.Width);
            textWriter.Write(" ");
            textWriter.Write(bmp.Height);
            textWriter.Write('\n');
            textWriter.Write(255);
            textWriter.Write('\n');
            textWriter.Close();

            BinaryWriter binaryWriter = new BinaryWriter(File.Open(filePath, FileMode.Append));
            unsafe
            {
                BitmapData bmpD = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
                int pointerAddress = (int)bmpD.Scan0;
                int extraBytes = bmpD.Stride - (bmp.Width * 3);
                int rowPerThread = bmp.Height / Environment.ProcessorCount;
                byte* p = (byte*)pointerAddress;
                for (int i = 0; i < bmp.Height; i++)
                {
                    for (int j = 0; j < bmp.Width; j++)
                    {
                        binaryWriter.Write(p[2]);
                        binaryWriter.Write(p[1]);
                        binaryWriter.Write(p[0]);

                        p += 3;
                    }

                    p += extraBytes;
                }

                bmp.UnlockBits(bmpD);
                binaryWriter.Close();
            }
        }

        /// <summary>
        /// Saves the p3 image.
        /// </summary>
        /// <param name="filePath">The file path.</param>
        /// <param name="bmp">The BMP.</param>
        private static void SaveP3(string filePath, Bitmap bmp)
        {
            TextWriter textWriter = new StreamWriter(filePath);
            textWriter.Write("P3\n# Image saved by PLACEHOLDER team.\n");
            textWriter.Write(bmp.Width);
            textWriter.Write(" ");
            textWriter.Write(bmp.Height);
            textWriter.Write('\n');
            textWriter.Write(255);
            textWriter.Write('\n');

            unsafe
            {
                BitmapData bmpD = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
                byte* p = (byte*)bmpD.Scan0;
                int counter = 0;
                int extraBytes = bmpD.Stride - (bmp.Width * 3);
                for (int i = 0; i < bmp.Height; i++)
                {
                    for (int j = 0; j < bmp.Width; j++)
                    {
                        textWriter.Write(p[2].ToString() + " ");
                        textWriter.Write(p[1].ToString() + " ");
                        textWriter.Write(p[0].ToString() + " ");
                        counter++;
                        if (counter == 8)
                        {
                            textWriter.Write('\n');
                            counter = 0;
                        }

                        p += 3;
                    }

                    p += extraBytes;
                }

                textWriter.Write('\n');
                bmp.UnlockBits(bmpD);
                textWriter.Close();
            }
        }

        /// <summary>
        /// Saves the p5.
        /// </summary>
        /// <param name="filePath">The file path.</param>
        /// <param name="bmp">The BMP.</param>
        private static void SaveP5(string filePath, Bitmap bmp)
        {
            TextWriter textWriter = new StreamWriter(filePath);
            textWriter.Write("P5\n# Image saved by PLACEHOLDER team.\n");
            textWriter.Write(bmp.Width);
            textWriter.Write(" ");
            textWriter.Write(bmp.Height);
            textWriter.Write('\n');
            textWriter.Write(255);
            textWriter.Write('\n');
            textWriter.Close();

            BinaryWriter binaryWriter = new BinaryWriter(File.Open(filePath, FileMode.Append));
            unsafe
            {
                BitmapData bmpD = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
                int pointerAddress = (int)bmpD.Scan0;
                int extraBytes = bmpD.Stride - (bmp.Width * 3);
                int rowPerThread = bmp.Height / Environment.ProcessorCount;
                byte* p = (byte*)pointerAddress;
                byte value = 0;
                for (int i = 0; i < bmp.Height; i++)
                {
                    for (int j = 0; j < bmp.Width; j++)
                    {
                        value = (byte)((p[0] + p[1] + p[2]) / 3);
                        binaryWriter.Write(value);

                        p += 3;
                    }

                    p += extraBytes;
                }

                bmp.UnlockBits(bmpD);
                binaryWriter.Close();
            }
        }
    }
}